#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "serialconnect.h"
#include "QMessageBox"
#include <QString>
#include <QByteArray>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMap>
#include <QFileDialog>
#include <synchapi.h>


MainWindow::MainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::MainWindow)
{
    pwd="/";
    fileRecString="";
    currentCmd="";

	ui->setupUi(this);
    setWindowTitle("nl-qt");
    setWindowIcon(QIcon(":/icons/images/Serial.png"));

	ui->label->setAutoFillBackground(true);
    ui->pushButton_open->setDisabled(true);
    ui->pushButton_download->setDisabled(true);

    baud_	= QSerialPort::Baud115200;
	serial.setBaudRate(baud_);
	serial.setDataBits(QSerialPort::Data8);
	serial.setParity(QSerialPort::NoParity);
	serial.setStopBits(QSerialPort::OneStop);
	serial.setFlowControl(QSerialPort::NoFlowControl);

	onUnconnected();
	serialConnect();

	connect(ui->pushButton_connect,SIGNAL(clicked(bool)),this,SLOT(serialConnect()));
	connect(ui->pushButton_disconnect,SIGNAL(clicked(bool)),this,SLOT(onDisconnect()));
	connect(&serial,SIGNAL(error(QSerialPort::SerialPortError)),this,SLOT(onSerialError(QSerialPort::SerialPortError)));
    connect(ui->pushButton_add, SIGNAL(clicked(bool)),this,SLOT(addFile()));
    connect(ui->pushButton_mkdir,SIGNAL(clicked(bool)),this,SLOT(onMkdirDialog()));
    connect(ui->pushButton_refresh,SIGNAL(clicked(bool)),this,SLOT(onRefreshFileList()));
    connect(ui->listWidget_files,&QListWidget::itemClicked,this,&MainWindow::onItemSelected);
    connect(ui->listWidget_files,&QListWidget::itemDoubleClicked,this,&MainWindow::onDoubleClicked);

    dialogMkdir = new DialogMkdir(this);
    connect(dialogMkdir, &DialogMkdir::confirmed,this,&MainWindow::onCreateDir);
    ui->labelProg->hide();
    ui->progressBar->hide();
}

MainWindow::~MainWindow()
{
	delete ui;
	disconnect(&serial,SIGNAL(error(QSerialPort::SerialPortError)),this,SLOT(onSerialError(QSerialPort::SerialPortError)));
	serial.close();
}

void MainWindow::serialConnect()
{
	static bool useable = true;
	if(!useable)
		return;
	useable = false;
	SerialConnect serc;
	serc.exec();
	QString str = serc.getPortName();
	if(str.isEmpty()){
		useable = true;
		if(serial.isOpen() && serial.isWritable()){
			return;
		}
		if(serial.isOpen())
			serial.close();
		onUnconnected();
		return;
	}
	if(serial.isOpen() && serial.isWritable()){
		if(str ==  serial.portName()){
			useable = true;
			return;
		}
		serial.close();
	}
	serial.setPortName(str);
	if (!serial.open(QIODevice::ReadWrite)){
		QMessageBox box;
		box.setText(tr("port %1 not available").arg(serial.portName()));
		box.setWindowTitle(tr("Port not available"));
		box.setIcon(QMessageBox::Critical);
		box.addButton(tr("Cancel"),QMessageBox::NoRole);
		QAbstractButton * retry	= box.addButton(tr("Retry"),QMessageBox::ActionRole);
		box.exec();
		if(box.clickedButton() == retry){
			useable = true;
			serialConnect();
			return;
		}
		else{
			onUnconnected();
			useable = true;
			return;
		}
	}
	useable = true;
	onConnected();
}

void MainWindow::onDisconnect()
{
	onUnconnected();
	if(serial.isOpen()){
		serial.close();
	}
}

void MainWindow::onConnected()
{
	ui->label->setText(serial.portName());
	QPalette palette = ui->label->palette();
    palette.setColor(ui->label->backgroundRole(), QColor(Qt::green).lighter(120));
	ui->label->setPalette(palette);

    currentCmd = "ls";

    onRefreshFileList();

}

void MainWindow::onUnconnected()
{
	ui->label->setText(tr("No Connection"));
	ui->label->setAutoFillBackground(true);
	QPalette palette = ui->label->palette();
    palette.setColor(ui->label->backgroundRole(),  QColor(Qt::red).lighter(120));
	ui->label->setPalette(palette);
}

void MainWindow::onSerialError(QSerialPort::SerialPortError error)
{
	if(error == QSerialPort::NoError)
		return;

    onDisconnect();
	if(error & QSerialPort::ResourceError){
		if(serial.isOpen())
			serial.close();
        QMessageBox box;
        box.setText("An Error occured on Port: "+serial.portName()+ \
                    "\nprobably the device has been removed"+ \
                    "\nSoftware Statemend: "+serial.errorString());
        box.setWindowTitle(tr("Port not available"));
		box.setIcon(QMessageBox::Critical);
		box.addButton(tr("Cancel"),QMessageBox::DestructiveRole);
		QAbstractButton * reconnect	= box.addButton(tr("Reconnect"),QMessageBox::ActionRole);
		box.exec();
		if(box.clickedButton() == reconnect){
			serialConnect();
		}
	}
	return;
}

void MainWindow::onBaudChanged(){
    int baud = 115200;

    baud_ = QSerialPort::BaudRate(baud);
	if(serial.isOpen() && serial.isWritable()){
		serial.close();
		serial.setBaudRate(baud_);
		onConnected();
		if(!serial.open(QIODevice::ReadWrite)){
			onSerialError(serial.error());
		}
	}
}

void MainWindow::sendCmd(QString CMD, QString ARG){

    if(!serial.isOpen() || !serial.isWritable())
        return;
    QString fullCmd = CMD+" "+ARG;
    serial.write(fullCmd.toUtf8());
    serial.waitForBytesWritten(1000);
}

QStringList MainWindow::parseRecFileData(QString DATA){
    QStringList fileList;

    QJsonDocument jsonDoc = QJsonDocument::fromJson(DATA.toUtf8());
    if(jsonDoc.isObject()){
        QJsonObject jsonObj = jsonDoc.object();
        int status = jsonObj.value("status").toInt();
        fileList.append(QString::number(status));
        if(status == 200){
            QJsonArray jsonFileArray = jsonObj.value("files").toArray();
            for (const QJsonValue& value : jsonFileArray) {
                fileList.append(value.toString());
            }
        }
        else{
        }
    }
    else{
        fileList.append("444");
    }
    return fileList;
}

void MainWindow::onRefreshFileList(){
    QByteArray data;
    char ch;
    sendCmd("ls", pwd);
    while(serial.waitForReadyRead(1000)){
        while (serial.bytesAvailable() > 0) {
            ch = serial.read(1)[0];
            data.append(ch);
            if (ch == '\n') {
                fileRecString = data;
                data.clear();
                break;
            }
        }
    }
    QStringList FILE_LIST = parseRecFileData(fileRecString.mid(11));
    ui->listWidget_files->clear();
    QListWidgetItem *backItem = new QListWidgetItem("..");
    backItem->setData(Qt::UserRole, "back");
    backItem->setIcon(QIcon(":/icons/images/Back.png"));
    ui->listWidget_files->addItem(backItem);
    if(FILE_LIST[0] == "200"){
        FILE_LIST.removeAt(0);
        for(const QString& item: FILE_LIST){
            QListWidgetItem *listItem = new QListWidgetItem(item.mid(1));
            if(item.startsWith("#")){
                listItem->setData(Qt::UserRole, "folder");
                listItem->setIcon(QIcon(":/icons/images/Folder.png"));
            }
            else if(item.startsWith("@")){
                listItem->setData(Qt::UserRole, "file");
                listItem->setIcon(QIcon(":/icons/images/File.png"));
            }
            ui->listWidget_files->addItem(listItem);
        }
    }
}

void MainWindow::onItemSelected(QListWidgetItem *item){
    QVariant roleData = item->data(Qt::UserRole);
    QString userRole = roleData.toString();
    if(userRole=="folder"){
        ui->pushButton_open->setEnabled(true);
        ui->pushButton_download->setDisabled(true);
    }
    else if(userRole=="file"){
        ui->pushButton_download->setEnabled(true);
        ui->pushButton_open->setDisabled(true);
    }
    else if(userRole == "back"){
        ui->pushButton_open->setDisabled(true);
        ui->pushButton_download->setDisabled(true);
    }
}

void MainWindow::onDoubleClicked(QListWidgetItem *item){
    QVariant roleData = item->data(Qt::UserRole);
    QString userRole = roleData.toString();
    if(userRole=="folder"||userRole=="back"){
        onChangePWD(item);
    }
    else if(userRole=="file"){
        onDownloadFile(item);
    }
}

void MainWindow::onDownloadFile(QListWidgetItem *item){
    sendCmd("cat", pwd+(item->text()));
    serial.waitForBytesWritten();
    QByteArray data;
    char ch;
    while(serial.waitForReadyRead(1000)){
        while (serial.bytesAvailable() > 0) {
            ch = serial.read(1)[0];
            data.append(ch);
            if (ch == '\n') {
                QString recv = data.mid(11);
                QString filedata;
                QJsonDocument jsonDoc = QJsonDocument::fromJson(recv.toUtf8());
                if(jsonDoc.isObject()){
                    QJsonObject jsonObj = jsonDoc.object();
                    int status = jsonObj.value("status").toInt();
                    if(status == 200){
                        filedata = jsonObj.value("data").toString();
                    }
                }
                QFile file;
                file.setFileName(item->text());
                file.open(QIODevice::WriteOnly);
                QTextStream out(&file);
                out<<filedata;
                file.close();
                data.clear();
                break;
            }
        }
    }
}

void MainWindow::onChangePWD(QListWidgetItem *item){
    QString folderName = item->text();
    if(folderName==".."){
        if(pwd!="/"){
            int backPointIndex = pwd.lastIndexOf('/', pwd.lastIndexOf('/')-1)+1;
            pwd=pwd.left(backPointIndex);
        }
        else{
            return;
        }
    }
    else{
        pwd.append(folderName);
        pwd.append('/');
        currentCmd = "ls";
    }

    onRefreshFileList();

}

void MainWindow::addFile(){
    QStringList fileNames = QFileDialog::getOpenFileNames(this, QStringLiteral("Choose file to upload"), "C:",QStringLiteral("All files(*.*)"));
    for(auto filename:fileNames){
        QFile file(filename);
        if(!file.open(QIODevice::ReadOnly | QIODevice::Text))qDebug()<<"failed to open file";
        QTextStream in(&file);
        QString alltext=in.readAll();
        QFileInfo fileInfo(filename);
        QString filenameOnly="";
        filenameOnly.append(fileInfo.fileName());
        sendCmd("write", pwd+filenameOnly+" "+alltext);
        serial.waitForBytesWritten();
        file.close();
    }
    onRefreshFileList();
}

void MainWindow::onMkdirDialog(){
    dialogMkdir -> show();
}

void MainWindow::onCreateDir(const QString &foldername){
    sendCmd("mkdir", pwd+foldername);
    currentCmd = "ls";
    Sleep(1000);
    onRefreshFileList();

}
